package org.budo.asr.service.aliyun;

import org.budo.asr.service.api.AsrRequest;
import org.budo.asr.service.api.AsrResponse;
import org.budo.support.lang.util.ThreadUtil;

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;

import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
@NoArgsConstructor
public class AliyunAsrService extends AbstractAliyunAsrService {
    public String submitFileRequest(String url) {
        long start = System.currentTimeMillis();

        CommonRequest postRequest = this.postRequest(url);

        /**
         * 3. 提交录音文件识别请求，获取录音文件识别请求任务的ID，以供识别结果查询使用
         */
        CommonResponse postResponse = this.acsClientCommonResponse(postRequest);
        if (postResponse.getHttpStatus() != 200) {
            log.error("#63 submitFileRequest, not 200 postResponse=" + postResponse + ", cost " + (System.currentTimeMillis() - start) + "ms");
            return null;
        }

        JSONObject jsonObject = JSONObject.parseObject(postResponse.getData());
        String statusText = jsonObject.getString(KEY_STATUS_TEXT);
        if (statusText.equals(STATUS_SUCCESS)) {
            log.info("#37 submitFileRequest, ok, jsonObject=" + jsonObject + ", cost " + (System.currentTimeMillis() - start) + "ms");
            return jsonObject.getString(KEY_TASK_ID);
        }

        log.error("#66 submitFileRequest error, jsonObject=" + jsonObject + ", cost " + (System.currentTimeMillis() - start) + "ms");
        return null;
    }

    public String getAsrResult(String taskId, Integer retry, Integer period) {
        long start = System.currentTimeMillis();

        CommonRequest request = this.getRequest(taskId);

        /**
         * 2. 提交录音文件识别结果查询请求 以轮询的方式进行识别结果的查询，直到服务端返回的状态描述为“SUCCESS”,或者为错误描述，则结束轮询。
         */
        int count = 0;
        String result = null;
        while (count < retry) {
            CommonResponse response = this.acsClientCommonResponse(request);
            if (response.getHttpStatus() != 200) { // 报错了
                log.error("#58 getAsrResult, 失败, response=" + response + ", reques=" + request + ", cost " + (System.currentTimeMillis() - start) + "ms");
                break;
            }

            if (!response.getData().contains("\"StatusCode\":21050000")) { // 还未成功
                log.info("#63 getAsrResult, 继续轮询, response=" + response + ", reques=" + request + ", cost " + (System.currentTimeMillis() - start) + "ms");
                ThreadUtil.sleep(period);
                count++;
                continue;
            }

            JSONObject rootObj = JSONObject.parseObject(response.getData());
            String statusText = rootObj.getString(KEY_STATUS_TEXT);

            // 失败 继续轮询，注意设置轮询时间间隔
            if (statusText.equals(STATUS_RUNNING) || statusText.equals(STATUS_QUEUEING)) {
                log.info("#74 getAsrResult, 继续轮询, response=" + response + ", reques=" + request + ", cost " + (System.currentTimeMillis() - start) + "ms");

                ThreadUtil.sleep(period);
                count++;
                continue; // 继续查结果
            }

            // 成功，返回识别结果；状态信息为异常，返回空
            if (statusText.equals(STATUS_SUCCESS)) {
                log.info("#83 getAsrResult, ok, response=" + response + ", reques=" + request + ", cost " + (System.currentTimeMillis() - start) + "ms");

                result = rootObj.getString(KEY_RESULT);
                break;
            }
        }

        return result;
    }

    @Override
    public AsrResponse recognition(AsrRequest request) {
        long start = System.currentTimeMillis();

        // 第一步：提交录音文件识别请求，获取任务ID用于后续的识别结果轮询
        String taskId = this.submitFileRequest(request.getUrl());
        if (taskId == null) {
            log.info("#87 recognition, 录音文件识别请求失败, cost " + (System.currentTimeMillis() - start) + "ms");
            return new AliyunAsrResponse();
        }

        Integer retry = null == request.getRetry() ? this.getRetry() : request.getRetry();
        Integer period = null == request.getPeriod() ? this.getPeriod() : request.getPeriod();

        // 第二步：根据任务ID轮询识别结果
        String responseBody = this.getAsrResult(taskId, retry, period);
        if (responseBody == null) {
            log.info("#97 recognition, 失败, taskId=" + taskId + ", cost " + (System.currentTimeMillis() - start) + "ms");
            return new AliyunAsrResponse();
        }

        log.info("#101 recognition, 成功, taskId=" + taskId + ", cost " + (System.currentTimeMillis() - start) + "ms");
        return new AliyunAsrResponse() //
                .setResponseBody(responseBody);
    }
}